﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

using ICSharpCode.SharpZipLib.Zip;

using Refix.Core.Properties;

namespace Refix.Core.Repository
{
    static public class RepositoryUtilities
    {
        static public void MergeZipFile(string baseDirectory, string targetDirectory, string zipFileName, MergeDirection direction)
        {
            new FastZip().ExtractZip(zipFileName, targetDirectory, "");
            File.Delete(zipFileName);
            MergeVersionFiles(baseDirectory, targetDirectory, direction);
        }

        static private void MergeVersionFiles(string baseDirectory, string targetDirectory, MergeDirection direction)
        {
            string existingVersionsFileName = Path.Combine(targetDirectory, "versions.xml");
            string downloadedVersionsFileName = Path.Combine(targetDirectory, "_versions.xml");
            if (!File.Exists(downloadedVersionsFileName))
            {
                return;
            }
            var xmlSerializer = new XmlSerializer(typeof(Component));
            var localRepository = new LocalRepository(baseDirectory);
            if (!File.Exists(existingVersionsFileName))
            {
                File.Move(downloadedVersionsFileName, existingVersionsFileName);
                Component newComponent;
                using (StreamReader stream = File.OpenText(existingVersionsFileName))
                {
                    newComponent = (Component)xmlSerializer.Deserialize(stream);
                }
                newComponent.RemoteRevision = newComponent.LocalRevision;
                localRepository.PutComponent(newComponent, false);
                return;
            }
            Component existingVersions;
            Component downloadedVersions;
            using (StreamReader stream = File.OpenText(existingVersionsFileName))
            {
                existingVersions = (Component)xmlSerializer.Deserialize(stream);
            }
            using (StreamReader stream = File.OpenText(downloadedVersionsFileName))
            {
                downloadedVersions = (Component)xmlSerializer.Deserialize(stream);
            }
            foreach (ComponentVersion componentVersion in downloadedVersions.Versions)
            {
                ComponentVersion componentVersionCopy = componentVersion;
                ComponentVersion match =
                    existingVersions.Versions.SingleOrDefault(v => v.Number == componentVersionCopy.Number);
                if (match == null)
                {
                    existingVersions.Versions.Add(componentVersion);
                }
                else
                {
                    foreach (AlternativeVersion alternativeVersion in componentVersion.AlternativeVersions)
                    {
                        AlternativeVersion alternativeVersionCopy = alternativeVersion;
                        if (!match.AlternativeVersions.Any(a => a.Number == alternativeVersionCopy.Number))
                        {
                            match.AlternativeVersions.Add(alternativeVersion);
                        }
                    }
                    if (!componentVersion.ReplaceWithVersion.IsNullOrEmpty())
                    {
                        match.ReplaceWithVersion = componentVersionCopy.ReplaceWithVersion;
                    }
                }
            }
            if (direction == MergeDirection.Download)
            {
                bool inSync = existingVersions.LocalRevision == existingVersions.RemoteRevision;
                if (!inSync)
                {
                    using (OutputWriter.Highlight(ConsoleColor.Yellow))
                    {
                        OutputWriter.WriteLine(OutputVerbosity.Quiet,
                            ResourceDispenser.GetString("MERGE_CONFLICTING_VERSION_BACKED_UP"), existingVersions.Name);
                    }   
                    localRepository.BackupVersionFile(existingVersions);
                }
                existingVersions.RemoteRevision = downloadedVersions.LocalRevision;
                if (inSync)
                {
                    existingVersions.LocalRevision = downloadedVersions.LocalRevision;
                }
                localRepository.PutComponent(existingVersions, !inSync);
            }
            else
            {
                localRepository.PutComponent(existingVersions, true);
            }
            File.Delete(downloadedVersionsFileName);
        }
    }
}